﻿
using System;
using System.Collections.Generic;

using System.Windows.Forms;

namespace GECS.Input {

	/// <summary>
	/// Constitutes all the information to take input polling for a game. You could
	/// use the static methods of the GKeyBoard and GMouse classes to check the key
	/// input.
	/// </summary>
    public class GInput {

		/// <summary>
		/// Input detection mode.
		/// </summary>
        public enum Behaviour {
			
			/// <summary>
			/// Normal Behaviour
			/// </summary>
            NORMAL,
            
			/// <summary>
			/// Only detect Initial inputs
			/// </summary>
            INITIAL_DETECT
        }

		/// <summary>
		/// An array of key actions.
		/// </summary>
        public static Action[] KEY_ACTIONS = new Action[Enum.GetNames(typeof(Keys)).Length];
        /// <summary>
        /// An array of mouse actions.
        /// </summary>
        public static Action[] MOUSE_ACTIONS = new Action[GMouse.NUM_MOUSE_CODES];

        /// <summary>
        /// Installs GInput as input listener to a form.
        /// </summary>
        /// <param name="f">The form which is the event source.</param>
        public GInput(Form f) {
            // Initialize the arrays
            for (int i=0; i<KEY_ACTIONS.Length; i++) {
                KEY_ACTIONS[i] = new Action();
            }
            for (int i=0; i<MOUSE_ACTIONS.Length; i++) {
                MOUSE_ACTIONS[i] = new Action();
            }
            MOUSE_ACTIONS[GMouse.MOUSE_CLICKED].DetectionType = Behaviour.INITIAL_DETECT;
            // Add the delegates
            f.KeyDown += delegate(object sender, KeyEventArgs e) { KeyDown(e); };
            f.KeyUp += delegate(object sender, KeyEventArgs e) { KeyUp(e); };
            f.MouseClick += delegate(object sender, MouseEventArgs e) { MouseClicked(e); };
            f.MouseDown += delegate(object sender, MouseEventArgs e) { MouseDown(e); };
            f.MouseUp += delegate(object sender, MouseEventArgs e) { MouseUp(e); };
            f.MouseMove += delegate(object sender, MouseEventArgs e) { MouseMoved(e); };
            f.MouseWheel += delegate(object sender, MouseEventArgs e) { MouseWheelMoved(e); };
        }
        
        /// <summary>
        /// Resets the input information.
        /// </summary>
        public void Reset(){
        	foreach (Action a in KEY_ACTIONS){
        		a.Reset();
        	}
        	foreach (Action a in MOUSE_ACTIONS){
        		a.Reset();
        	}
        }
        
        /// <summary>
        /// Sets the detection type of a key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="b"></param>
        public static void SetDetectionType(Keys key, Behaviour b){
        	KEY_ACTIONS[(int)key].DetectionType = b;
        }
        
        /// <summary>
        /// Converts the MouseButtons enum value to GMouse mouse codes.
        /// </summary>
        /// <param name="button">The MouseButtons enum value.</param>
        /// <returns>The mouse code of the button.</returns>
        public static int GetMouseButton(MouseButtons button){
        	switch (button){
        		case MouseButtons.Left: return GMouse.MOUSE_BUTTON_1;
        		case MouseButtons.Middle: return GMouse.MOUSE_BUTTON_2;
        		case MouseButtons.Right: return GMouse.MOUSE_BUTTON_3;
        	}
        	return -1;
        }

        private void KeyDown(KeyEventArgs e) {
            KEY_ACTIONS[(int)e.KeyCode].Press();
        }

        private void KeyUp(KeyEventArgs e) {
            KEY_ACTIONS[(int)e.KeyCode].Release();
        }

        private void MouseClicked(MouseEventArgs e) {
			Action click = MOUSE_ACTIONS[GMouse.MOUSE_CLICKED];
        	if (!click.IsPressed()){
            	click.Press();
            	GMouse.MOUSE_CLICK_X = e.X;
            	GMouse.MOUSE_CLICK_Y = e.Y;
        	}
        }

        private void MouseDown(MouseEventArgs e) {
        	MOUSE_ACTIONS[GetMouseButton(e.Button)].Press();
        }

        private void MouseUp(MouseEventArgs e) {
        	MOUSE_ACTIONS[GetMouseButton(e.Button)].Release();
        }

        private void MouseMoved(MouseEventArgs e) {
			int dx = e.X - GMouse.X;
			int dy = e.Y - GMouse.Y;
			if (dx < 0){
				MOUSE_ACTIONS[GMouse.MOUSE_MOVE_LEFT].Press(Math.Abs(dx));
			} else {
				MOUSE_ACTIONS[GMouse.MOUSE_MOVE_RIGHT].Press(dx);
			}
			if (dy < 0){
				MOUSE_ACTIONS[GMouse.MOUSE_MOVE_UP].Press(Math.Abs(dy));
			} else {
				MOUSE_ACTIONS[GMouse.MOUSE_WHEEL_DOWN].Press(dy);
			}
			GMouse.X = e.X;
			GMouse.Y = e.Y;
        }

        private void MouseWheelMoved(MouseEventArgs e) {
			int amount = e.Delta;
			if (amount < 0){
				MOUSE_ACTIONS[GMouse.MOUSE_WHEEL_UP].Press(Math.Abs(amount));
			} else {
				MOUSE_ACTIONS[GMouse.MOUSE_WHEEL_DOWN].Press(Math.Abs(amount));
			}
        }

    }

}
